package cn.sgjk.train.business.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.sgjk.train.business.domain.Train;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import cn.sgjk.train.common.resp.PageResp;
import cn.sgjk.train.common.util.SnowUtil;
import cn.sgjk.train.business.domain.DailyTrain;
import cn.sgjk.train.business.domain.DailyTrainExample;
import cn.sgjk.train.business.mapper.DailyTrainMapper;
import cn.sgjk.train.business.req.DailyTrainQueryReq;
import cn.sgjk.train.business.req.DailyTrainSaveReq;
import cn.sgjk.train.business.resp.DailyTrainQueryResp;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;

@Service
public class DailyTrainService {

    private static final Logger LOG = LoggerFactory.getLogger(DailyTrainService.class);

    @Resource
    private DailyTrainMapper dailyTrainMapper;

    @Autowired
    private TrainService trainService;

    @Autowired
    private DailyTrainStationService dailyTrainStationService;

    @Autowired
    private DailyTrainCarriageService dailyTrainCarriageService;

    @Autowired
    private DailyTrainSeatService dailyTrainSeatService;

    @Autowired
    private DailyTrainTicketService dailyTrainTicketService;

    @Autowired
    private SkTokenService skTokenService;

    @Autowired
    private RedisTemplate redisTemplate;



    public void save(DailyTrainSaveReq req) {
        DateTime now = DateTime.now();
        DailyTrain dailyTrain = BeanUtil.copyProperties(req, DailyTrain.class);
        if (ObjectUtil.isNull(dailyTrain.getId())) {
            dailyTrain.setId(SnowUtil.getSnowflakeNextId());
            dailyTrain.setCreateTime(now);
            dailyTrain.setUpdateTime(now);
            dailyTrainMapper.insert(dailyTrain);
        } else {
            dailyTrain.setUpdateTime(now);
            dailyTrainMapper.updateByPrimaryKey(dailyTrain);
        }
    }

    public PageResp<DailyTrainQueryResp> queryList(DailyTrainQueryReq req) {
        DailyTrainExample dailyTrainExample = new DailyTrainExample();
        dailyTrainExample.setOrderByClause("date desc, code asc");
        DailyTrainExample.Criteria criteria = dailyTrainExample.createCriteria();
        if(ObjectUtil.isNotNull(req.getDate())) {
            criteria.andDateEqualTo(req.getDate());
        }

        if(ObjectUtil.isNotEmpty(req.getCode())) {
            criteria.andCodeEqualTo(req.getCode());
        }

        LOG.info("查询页码：{}", req.getPage());
        LOG.info("每页条数：{}", req.getSize());
        PageHelper.startPage(req.getPage(), req.getSize());
        List<DailyTrain> dailyTrainList = dailyTrainMapper.selectByExample(dailyTrainExample);

        PageInfo<DailyTrain> pageInfo = new PageInfo<>(dailyTrainList);
        LOG.info("总行数：{}", pageInfo.getTotal());
        LOG.info("总页数：{}", pageInfo.getPages());

        List<DailyTrainQueryResp> list = BeanUtil.copyToList(dailyTrainList, DailyTrainQueryResp.class);

        PageResp<DailyTrainQueryResp> pageResp = new PageResp<>();
        pageResp.setTotal(pageInfo.getTotal());
        pageResp.setList(list);
        return pageResp;
    }

    public void delete(Long id) {
        dailyTrainMapper.deleteByPrimaryKey(id);
    }


    /**
     *  生成某日的所有车次信息，包括车站，车厢，车座
     */

    @Transactional
    public void genAll(Date date) {

        List<Train> trains = trainService.selectAll();
        if(CollUtil.isEmpty(trains)) {
            // 一般获取列表都做判空逻辑
            LOG.info("没有车次的基本数据");
            return;
        }
        int trainSum = trains.size();
        CountDownLatch downLatch = new CountDownLatch(trainSum);
        for (Train train : trains) {
            LOG.info("开始生成{}车次",train.getCode());
            new Thread(()->{
                long start = System.currentTimeMillis();
                genDaily(date, train);
                long end = System.currentTimeMillis();
                downLatch.countDown();

                // 移除无余票标识
                removeKey(date,train.getCode());
                LOG.info("生成{}车次完成,用时{}",train.getCode(),(end - start));
            }).start();

        }
        try {
            downLatch.await();
        } catch (InterruptedException e) {
            LOG.error("每日车次生成失败",e);
        }
        LOG.info("每日车次生成成功");
    }


    private void genDaily(Date date, Train train) {
        //生成前进行判断是否生成过数据了  在循环体进行判断  高内聚低耦合  删除已有当天数据
        LOG.info("生成日期【{}】车次【{}】的信息开始", DateUtil.formatDate(date), train.getCode());
        DailyTrainExample dailyTrainExample = new DailyTrainExample();
        dailyTrainExample.createCriteria()
                .andDateEqualTo(date)
                .andCodeEqualTo(train.getCode());
        dailyTrainMapper.deleteByExample(dailyTrainExample);

        // 生成该车次的数据
        DateTime now = new DateTime();
        DailyTrain dailyTrain = BeanUtil.copyProperties(train, DailyTrain.class);
        dailyTrain.setId(SnowUtil.getSnowflakeNextId());
        dailyTrain.setCreateTime(now);
        dailyTrain.setUpdateTime(now);
        dailyTrain.setDate(date);
        dailyTrainMapper.insert(dailyTrain);


        // 生成该车次的车站数据
        dailyTrainStationService.genAll(date,train.getCode());
        // 生成该车次的车厢数据
        dailyTrainCarriageService.genCarriage(date,train.getCode());
        // 生成该车次的座位数据
        dailyTrainSeatService.genSeat(date,train.getCode());
        // 生成该车次的余票数据
        dailyTrainTicketService.genTicket(date,train);
        // 生成该车次的令牌数据
        skTokenService.genDaily(date,train.getCode());

        LOG.info("生成日期【{}】车次【{}】的信息结束", DateUtil.formatDate(date), train.getCode());

    }

    private void removeKey(Date date, String code) {
        String isNotTicketKey = DateUtil.format(date,"yyyy-MM-dd") + code + "NotTicketKey";
        Boolean delete = redisTemplate.delete(isNotTicketKey);
    }

}
